import logging
import datetime
from typing import Optional, Dict, Any, List

import kopf
from kopf import Body
from kubernetes import client, config
from kubernetes.client.rest import ApiException

from .api import Website, WebsitePhase, WebsiteConditionType, API_VERSION, KIND, GROUP, VERSION, PLURAL
from .resource_manager import WebsiteResourceManager, WebsiteResourceType


# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def generate_resource_name(base_name: str) -> str:
    """生成一致的资源名称
    
    Args:
        base_name: 基础资源名称
        
    Returns:
        str: 组合后的资源名称
    """
    return f"website-{base_name}"


@kopf.on.login()
def on_login(**kwargs):
    """Kubernetes认证配置"""
    try:
        config.load_incluster_config()
    except config.config_exception.ConfigException:
        config.load_kube_config()
    info =  kopf.login_via_client(**kwargs)
    logger.info(f"Kubernetes info: {info}")
    return info


@kopf.on.startup()
def on_startup(settings: kopf.OperatorSettings, logger: logging.Logger, **kwargs):
    """Operator启动时的初始化"""
    logger.info("Website Controller starting up...")
    settings.posting.level = logging.INFO
    settings.posting.enabled = True


@kopf.on.create(GROUP, VERSION, KIND)
def on_website_create(name: str, namespace: Optional[str], body: Body, logger: logging.Logger, **kwargs):
    """处理Website创建事件"""
    logger.info(f'Newly created Website resource named {name} in namespace {namespace}, start to reconciling...')

    website = Website(body)

    try:
        website.parse_spec()
        website.get_spec().validate(logger)
    except Exception as e:
        website.update_status({
            'phase': WebsitePhase.FAILED.value,
            'conditions': [],
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z',
            'observedGeneration': body['metadata'].get('generation', 1)
        })
        website.error(action='CreateWebsite',
                     reason='InvalidSpecArgument', msg=str(e))
        raise kopf.TemporaryError(f"Error found in Website spec: {e}")

    website_spec = website.get_spec()
    website.self_logging(logger)

    try:
        # 初始化资源管理器
        resource_manager = WebsiteResourceManager(
            namespace=namespace,
            logger=logger
        )

        # 更新状态为Creating
        website.update_status({
            'phase': WebsitePhase.CREATING.value,
            'conditions': [],
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z',
            'observedGeneration': body['metadata'].get('generation', 1)
        })

        # 创建Deployment
        logger.info(f"Creating deployment for website {name}")
        resource_manager.create_resource(WebsiteResourceType.DEPLOYMENT, website)

        # 创建Service
        logger.info(f"Creating service for website {name}")
        resource_manager.create_resource(WebsiteResourceType.SERVICE, website)

        # 等待Deployment就绪
        logger.info(f"Waiting for deployment to be ready for website {name}")
        deployment_ready = resource_manager.wait_for_deployment_ready(name, timeout=60)

        # 更新状态
        conditions = []
        if deployment_ready:
            conditions = add_condition(
                conditions,
                WebsiteConditionType.DEPLOYMENT_READY.value,
                "True",
                "DeploymentReady",
                "Deployment is ready"
            )
            conditions = add_condition(
                conditions,
                WebsiteConditionType.SERVICE_READY.value,
                "True",
                "ServiceReady",
                "Service is ready"
            )
            conditions = add_condition(
                conditions,
                WebsiteConditionType.HEALTHY.value,
                "True",
                "Healthy",
                "Website is healthy"
            )
            phase = WebsitePhase.RUNNING.value
        else:
            conditions = add_condition(
                conditions,
                WebsiteConditionType.DEPLOYMENT_READY.value,
                "False",
                "DeploymentNotReady",
                "Deployment is not ready"
            )
            phase = WebsitePhase.FAILED.value

        website.update_status({
            'phase': phase,
            'conditions': conditions,
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z',
            'observedGeneration': body['metadata'].get('generation', 1)
        })

        # 记录成功事件
        website.info(action='CreateWebsite', reason='WebsiteResourcesCreated',
                    msg='Website resources created successfully')

    except Exception as e:
        website.warn(action='CreateWebsite',
                    reason='WebsiteResourcesFailedReconciliation', msg=str(e))
        raise


@kopf.on.update(GROUP, VERSION, KIND)
def on_website_update(name: str, namespace: Optional[str], body: Body, logger: logging.Logger, **kwargs):
    """处理Website更新事件"""
    logger.info(f'Website {name} in namespace {namespace} was updated, start to reconciling...')

    website = Website(body)

    try:
        website.parse_spec()
        website.get_spec().validate(logger)
    except Exception as e:
        website.update_status({
            'phase': WebsitePhase.FAILED.value,
            'conditions': [],
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z',
            'observedGeneration': body['metadata'].get('generation', 1)
        })
        website.error(action='UpdateWebsite',
                     reason='InvalidSpecArgument', msg=str(e))
        raise kopf.TemporaryError(f"Error found in Website spec: {e}")

    website_spec = website.get_spec()
    website.self_logging(logger)

    try:
        # 初始化资源管理器
        resource_manager = WebsiteResourceManager(
            namespace=namespace,
            logger=logger
        )

        # 更新Deployment
        logger.info(f"Updating deployment for website {name}")
        resource_manager.update_resource(WebsiteResourceType.DEPLOYMENT, website)

        # 更新Service
        logger.info(f"Updating service for website {name}")
        resource_manager.update_resource(WebsiteResourceType.SERVICE, website)

        # 等待Deployment就绪
        logger.info(f"Waiting for deployment to be ready for website {name}")
        deployment_ready = resource_manager.wait_for_deployment_ready(name, timeout=60)

        # 更新状态
        conditions = []
        if deployment_ready:
            conditions = add_condition(
                conditions,
                WebsiteConditionType.DEPLOYMENT_READY.value,
                "True",
                "DeploymentUpdated",
                "Deployment updated successfully"
            )
            conditions = add_condition(
                conditions,
                WebsiteConditionType.SERVICE_READY.value,
                "True",
                "ServiceUpdated",
                "Service updated successfully"
            )
            conditions = add_condition(
                conditions,
                WebsiteConditionType.HEALTHY.value,
                "True",
                "Healthy",
                "Website is healthy"
            )
            phase = WebsitePhase.RUNNING.value
        else:
            conditions = add_condition(
                conditions,
                WebsiteConditionType.DEPLOYMENT_READY.value,
                "False",
                "DeploymentNotReady",
                "Deployment is not ready after update"
            )
            phase = WebsitePhase.FAILED.value

        website.update_status({
            'phase': phase,
            'conditions': conditions,
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z',
            'observedGeneration': body['metadata'].get('generation', 1)
        })

        # 记录成功事件
        website.info(action='UpdateWebsite', reason='WebsiteResourcesUpdated',
                    msg='Website resources updated successfully')

    except Exception as e:
        website.warn(action='UpdateWebsite',
                    reason='WebsiteResourcesFailedReconciliation', msg=str(e))
        raise


@kopf.on.delete(GROUP, VERSION, KIND)
def on_website_delete(name: str, namespace: Optional[str], body: Body, logger: logging.Logger, **kwargs):
    """处理Website删除事件"""
    logger.info(f'Website {name} in namespace {namespace} is being deleted, cleaning up associated resources...')

    website = Website(body)
    website.self_logging(logger)

    try:
        # 初始化资源管理器
        resource_manager = WebsiteResourceManager(
            namespace=namespace,
            logger=logger
        )

        # 更新状态为Terminating
        website.update_status({
            'phase': WebsitePhase.TERMINATING.value,
            'lastUpdateTime': datetime.datetime.utcnow().isoformat() + 'Z'
        })

        # 删除资源（由于设置了ownerReferences，Deployment和Service会自动被删除）
        # 这里我们只需要记录日志
        logger.info(f"Deployment and Service for website {name} will be automatically deleted due to owner references")
        logger.info(f"Website {namespace}/{name} cleanup completed")

    except Exception as e:
        logger.error(f"Failed to cleanup Website {namespace}/{name}: {e}")
        raise kopf.TemporaryError(f"Failed to cleanup Website: {e}", delay=10)


def add_condition(conditions: List[Dict], condition_type: str, status: str,
                  reason: str, message: str) -> List[Dict]:
    """添加状态条件"""
    now = datetime.datetime.utcnow().isoformat() + 'Z'

    # 查找是否已存在相同类型的条件
    for condition in conditions:
        if condition['type'] == condition_type:
            condition['status'] = status
            condition['lastTransitionTime'] = now
            condition['reason'] = reason
            condition['message'] = message
            return conditions

    # 添加新条件
    conditions.append({
        'type': condition_type,
        'status': status,
        'lastTransitionTime': now,
        'reason': reason,
        'message': message
    })

    return conditions


if __name__ == "__main__":
    # 运行Operator
    kopf.run()